﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;

namespace SemantEx
{
	public class RegexValidationParser : LambdaParser
	{
		#region Constructors

		protected RegexValidationParser(Regex regex, string input, IParameterScope scope = null)
			: base(input, scope)
		{
			Regex = regex;
		}

		#endregion

		#region Properties

		public Regex Regex { get; private set; }

		public string GroupName { get; set; }

		#endregion

		#region Methods

		public static ValidatorInfo Parse(Regex regex, string expression, IParameterScope scope = null)
		{
			var parser = new RegexValidationParser(regex, expression, scope);
			dynamic func = new DynamicInvocation(parser.Evaluate());
			return new ValidatorInfo()
			{
				GroupName = parser.GroupName,
				Validation = x => (bool)func(x)
			};
		}

		protected override Delegate Evaluate()
		{
			Lexer.SkipWhiteSpace();
			var expr = base.ReadExpression();
			GroupName = expr.Parameters.First().Name;
			var func = expr.Compile();
			Lexer.ValidateEOF();
			return func;
		}

		protected override Expression ReadSymbol(string ident)
		{
			if (!Regex.GetGroupNames().Any(x => x == ident))
			{
				Lexer.ThrowException("'{0}' is not a valid group name for this regular expression.", ident);
			}
			if (!Scope.Parameters.Any(x => x.Name == ident) && (Scope.Parameters.Count() == 1))
			{
				Lexer.ThrowException("Cannot define '{0}' for this expression; a group name has already been defined.", ident);
			}
			return Scope.FindSymbol(ident);
		}

		#endregion
	}
}